(function() {
  var GameInput, Input, KeyCode, aabbIntersect, all, c, calculateDeflection, calculateSlide, contexts, fragFont, fragShape, identity, k, line, mult, primitiveSizeLookup, sign, sweptAABB, vertFont, vertShape;

  window.Font437 = (function() {
    function Font437(ctx) {
      var me;
      this.ready = false;
      this.fontTex = ctx.Texture();
      me = this;
      this.spr = ctx.SpriteRender();
      this.promise = this.fontTex.load("img/font.png").then(function() {
        me.ready = true;
        return me.spr.setSpriteSheet(me.fontTex, 8, 8);
      });
      this.worldTransform = new window.Transform2D();
      this.localTransform = new window.Transform2D();
      this.spr.setWorldTransform(this.worldTransform);
    }

    Font437.prototype.use = function() {
      return this.spr.use();
    };

    Font437.prototype.drawOutlined = function(x, y, string, scale, r, g, b, a) {
      this.setColor(0.0, 0.0, 0.0, 1.0);
      this.drawString(x + scale, y, string, scale);
      this.setColor(r, g, b, a);
      return this.drawString(x, y, string, scale);
    };

    Font437.prototype.setColor = function(x, y, z, w) {
      return this.spr.setColor(x, y, z, w);
    };

    Font437.prototype.drawString = function(x, y, string, scale) {
      var charCode, column, row, _i, _ref;
      if (!this.ready) {
        return false;
      }
      if (scale == null) {
        scale = 1.0;
      }
      this.localTransform.setScale(scale);
      this.localTransform.setTranslation(x, y);
      for (x = _i = 0, _ref = string.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; x = 0 <= _ref ? ++_i : --_i) {
        charCode = string.charCodeAt(x);
        column = charCode >> 5;
        row = charCode - (column << 5);
        this.spr.drawSprite([row * 8, column * 8], this.localTransform);
        this.localTransform.translate(8 * scale, 0);
      }
      return true;
    };

    return Font437;

  })();

  contexts = {};

  window.Context = (function() {
    function Context(name, w, h) {
      this.name = name;
      if (w == null) {
        w = 800;
      }
      if (h == null) {
        h = 400;
      }
      contexts[this.name] = this;
      this.canvas = document.createElement("canvas");
      document.body.appendChild(this.canvas);
      this.gl = this.canvas.getContext("webgl", {
        premultipliedAlpha: false,
        alpha: false
      } || this.canvas.getContext("experimental-webgl", {
        premultipliedAlpha: false,
        alpha: false
      }));
      this.gl.enable(this.gl.BLEND);
      this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
      this.gl.clearColor(1, 1, 1, 1);
      this.gl.clear(this.gl.COLOR_BUFFER_BIT);
      this.gl.pixelStorei(this.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
      this.gl.colorMask(true, true, true, false);
      this.setWidth(w);
      this.setHeight(h);
      this.clearColor(0.0, 0.0, 0.0, 1.0);
      this.clear();
    }

    Context.prototype.clearColor = function(x, y, z, w) {
      if (x == null) {
        x = 1.0;
      }
      if (y == null) {
        y = x;
      }
      if (z == null) {
        z = y;
      }
      if (w == null) {
        w = 1.0;
      }
      return this.gl.clearColor(x, y, z, w);
    };

    Context.prototype.getCanvas = function() {
      return this.canvas;
    };

    Context.prototype.screen = function() {
      return {
        x: 1.0 / (this.canvas.width / 2.0),
        y: -1.0 / (this.canvas.height / 2.0)
      };
    };

    Context.prototype.setWidth = function(w) {
      this.canvas.width = w;
      return this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
    };

    Context.prototype.setHeight = function(h) {
      this.canvas.height = h;
      return this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
    };

    Context.prototype.clear = function() {
      return this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
    };

    Context.prototype.Texture = function() {
      return new window.Texture(this);
    };

    Context.prototype.Program = function() {
      return new window.Program(this);
    };

    Context.prototype.MeshBuffer = function(defaultSize) {
      return new window.MeshBuffer(this, defaultSize);
    };

    Context.prototype.SpriteRender = function() {
      return new window.SpriteRender(this);
    };

    Context.prototype.Font437 = function() {
      return new window.Font437(this);
    };

    return Context;

  })();

  window.getContext = function(name) {
    return contexts[name];
  };

  window.loadImage = function(src) {
    var defer, img;
    defer = new window.mq.Defer();
    img = new Image;
    img.src = src;
    img.onload = function() {
      return defer.resolve(img);
    };
    return defer;
  };

  KeyCode = {
    CANCEL: 3,
    HELP: 6,
    BACK_SPACE: 8,
    TAB: 9,
    CLEAR: 12,
    RETURN: 13,
    ENTER: 14,
    SHIFT: 16,
    CONTROL: 17,
    ALT: 18,
    PAUSE: 19,
    CAPS_LOCK: 20,
    ESCAPE: 27,
    SPACE: 32,
    PAGE_UP: 33,
    PAGE_DOWN: 34,
    END: 35,
    HOME: 36,
    LEFT: 37,
    UP: 38,
    RIGHT: 39,
    DOWN: 40,
    PRINTSCREEN: 44,
    INSERT: 45,
    DELETE: 46,
    0: 48,
    1: 49,
    2: 50,
    3: 51,
    4: 52,
    5: 53,
    6: 54,
    7: 55,
    8: 56,
    9: 57,
    SEMICOLON: 59,
    EQUALS: 61,
    A: 65,
    B: 66,
    C: 67,
    D: 68,
    E: 69,
    F: 70,
    G: 71,
    H: 72,
    I: 73,
    J: 74,
    K: 75,
    L: 76,
    M: 77,
    N: 78,
    O: 79,
    P: 80,
    Q: 81,
    R: 82,
    S: 83,
    T: 84,
    U: 85,
    V: 86,
    W: 87,
    X: 88,
    Y: 89,
    Z: 90,
    CONTEXT_MENU: 93,
    NUMPAD0: 96,
    NUMPAD1: 97,
    NUMPAD2: 98,
    NUMPAD3: 99,
    NUMPAD4: 100,
    NUMPAD5: 101,
    NUMPAD6: 102,
    NUMPAD7: 103,
    NUMPAD8: 104,
    NUMPAD9: 105,
    MULTIPLY: 106,
    ADD: 107,
    SEPARATOR: 108,
    SUBTRACT: 109,
    DECIMAL: 110,
    DIVIDE: 111,
    F1: 112,
    F2: 113,
    F3: 114,
    F4: 115,
    F5: 116,
    F6: 117,
    F7: 118,
    F8: 119,
    F9: 120,
    F10: 121,
    F11: 122,
    F12: 123,
    F13: 124,
    F14: 125,
    F15: 126,
    F16: 127,
    F17: 128,
    F18: 129,
    F19: 130,
    F20: 131,
    F21: 132,
    F22: 133,
    F23: 134,
    F24: 135,
    NUM_LOCK: 144,
    SCROLL_LOCK: 145,
    COMMA: 188,
    PERIOD: 190,
    SLASH: 191,
    BACK_QUOTE: 192,
    OPEN_BRACKET: 219,
    BACK_SLASH: 220,
    CLOSE_BRACKET: 221,
    QUOTE: 222,
    META: 224
  };

  Input = {
    state: {},
    isDown: function(code) {
      return this.state[code];
    }
  };

  all = [];

  for (k in KeyCode) {
    c = KeyCode[k];
    Input.state[c] = false;
    all.push(k);
  }

  GameInput = {
    createKey: function(name, keycodes) {
      if (keycodes.length === void 0) {
        keycodes = [keycodes];
      }
      keycodes = (function() {
        var _i, _len, _results;
        _results = [];
        for (_i = 0, _len = keycodes.length; _i < _len; _i++) {
          k = keycodes[_i];
          _results.push(KeyCode[k]);
        }
        return _results;
      })();
      GameInput[name] = {
        isDown: function() {
          var _i, _len;
          for (_i = 0, _len = keycodes.length; _i < _len; _i++) {
            k = keycodes[_i];
            if (Input.isDown(k)) {
              return true;
            }
          }
          return false;
        },
        isUp: function() {
          var _i, _len;
          for (_i = 0, _len = keycodes.length; _i < _len; _i++) {
            k = keycodes[_i];
            if (Input.isDown(k)) {
              return false;
            }
          }
          return true;
        }
      };
      return void 0;
    }
  };

  window.onkeydown = function(e) {
    return Input.state[e.which] = true;
  };

  window.onkeyup = function(e) {
    return Input.state[e.which] = false;
  };

  GameInput.createKey("any", all);

  window.Input = GameInput;

  primitiveSizeLookup = {
    FLOAT: 4,
    BYTE: 1,
    SHORT: 2,
    UNSIGNED_BYTE: 1,
    UNSIGNED_SHORT: 2
  };

  window.MeshBuffer = (function() {
    function MeshBuffer(ctx, defaultSize) {
      this.ctx = ctx;
      this.gl = this.ctx.gl;
      this.stride = 0;
      this.description = [];
      if (defaultSize == null) {
        defaultSize = 10000;
      }
      this.vsize = defaultSize;
      this.vhead = 0;
      this.isize = defaultSize;
      this.ihead = 0;
      this.verts = new Float32Array(this.vsize);
      this.idx = new Uint16Array(this.isize);
      this.idxBuff = this.gl.createBuffer();
      this.vertBuff = this.gl.createBuffer();
      this.vertexUsage = this.gl.STREAM_DRAW;
      this.indexUsage = this.gl.STREAM_DRAW;
    }

    MeshBuffer.prototype.clear = function() {
      this.vhead = 0;
      return this.ihead = 0;
    };

    MeshBuffer.prototype.addDescription = function(name, type, size, normalized) {
      if (normalized == null) {
        normalized = false;
      }
      this.description.push({
        name: name,
        type: this.gl[type],
        size: size,
        offset: this.stride,
        normalized: normalized
      });
      return this.stride += size * primitiveSizeLookup[type];
    };

    MeshBuffer.prototype.bindBuffers = function() {
      this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertBuff);
      return this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.idxBuff);
    };

    MeshBuffer.prototype.finalize = function() {
      this.verts = new Float32Array(this.verts.subarray(0, this.vhead + 1));
      return this.idx = new Float32Array(this.idx.subarray(0, this.ihead + 1));
    };

    MeshBuffer.prototype.upload = function() {
      this.bindBuffers();
      this.gl.bufferData(this.gl.ARRAY_BUFFER, this.verts, this.vertexUsage);
      return this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, this.idx, this.indexUsage);
    };

    MeshBuffer.prototype.pushf = function(x) {
      this.resizeVertsIfNeeded(1);
      this.verts[this.vhead] = x;
      return this.vhead += 1;
    };

    MeshBuffer.prototype.pushff = function(x, y) {
      this.resizeVertsIfNeeded(2);
      this.verts[this.vhead] = x;
      this.verts[this.vhead + 1] = y;
      return this.vhead += 2;
    };

    MeshBuffer.prototype.pushfff = function(x, y, z) {
      this.resizeVertsIfNeeded(3);
      this.verts[this.vhead] = x;
      this.verts[this.vhead + 1] = y;
      this.verts[this.vhead + 2] = z;
      return this.vhead += 3;
    };

    MeshBuffer.prototype.pushffff = function(x, y, z, w) {
      this.resizeVertsIfNeeded(4);
      this.verts[this.vhead] = x;
      this.verts[this.vhead + 1] = y;
      this.verts[this.vhead + 2] = z;
      this.verts[this.vhead + 3] = w;
      return this.vhead += 4;
    };

    MeshBuffer.prototype.setup = function(program) {
      var desc, loc, _i, _len, _ref, _results;
      this.bindBuffers();
      _ref = this.description;
      _results = [];
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        desc = _ref[_i];
        loc = this.gl.getAttribLocation(program.program, desc.name);
        this.gl.enableVertexAttribArray(loc);
        if (loc === -1) {
          console.error("Vertex attribute " + desc.name + " does not exist in shader");
        }
        _results.push(this.gl.vertexAttribPointer(loc, desc.size, desc.type, desc.normalized, this.stride, desc.offset));
      }
      return _results;
    };

    MeshBuffer.prototype.draw = function(mode, first, count) {
      if (first == null) {
        first = 0;
      }
      if (count == null) {
        count = this.ihead;
      }
      if (mode == null) {
        mode = this.gl.TRIANGLES;
      }
      return this.gl.drawElements(mode, count, this.gl.UNSIGNED_SHORT, first);
    };

    MeshBuffer.prototype.pushi = function(x) {
      this.resizeIdxIfNeeded(1);
      this.idx[this.ihead] = x;
      return this.ihead += 1;
    };

    MeshBuffer.prototype.pushii = function(x, y) {
      this.resizeIdxIfNeeded(2);
      this.idx[this.ihead] = x;
      this.idx[this.ihead + 1] = y;
      return this.ihead += 2;
    };

    MeshBuffer.prototype.pushiii = function(x, y, z) {
      this.resizeIdxIfNeeded(3);
      this.idx[this.ihead] = x;
      this.idx[this.ihead + 1] = y;
      this.idx[this.ihead + 2] = z;
      return this.ihead += 3;
    };

    MeshBuffer.prototype.resizeVertsIfNeeded = function(size) {
      var newBuff, newSize;
      if (this.vsize > this.vhead + size) {
        return false;
      }
      console.log("resizing vertices");
      newSize = this.vsize + this.vsize / 2;
      newBuff = new Float32Array(newSize);
      newBuff.set(this.verts);
      this.verts = newBuff;
      return this.vsize = newSize;
    };

    MeshBuffer.prototype.resizeIdxIfNeeded = function(size) {
      var newBuff, newSize;
      if (this.isize > this.ihead + size) {
        return false;
      }
      console.log("resizing index");
      newSize = this.isize + this.isize / 2;
      newBuff = new Uint16Array(newSize);
      newBuff.set(this.idx);
      this.idx = newBuff;
      return this.isize = newSize;
    };

    return MeshBuffer;

  })();

  window.mq = {};

  window.mq.Defer = (function() {
    function Defer() {
      this.pending = [];
      this.resolved = false;
      this.data = null;
    }

    Defer.prototype.then = function(fn) {
      var d;
      d = new window.mq.Defer();
      if (this.resolved) {
        d.resolve(fn(this.data));
      }
      if (!this.resolved) {
        this.pending.push([fn, d]);
      }
      return d;
    };

    Defer.prototype.resolve = function(data) {
      var dd, _i, _len, _ref, _results;
      this.data = data;
      this.resolved = true;
      _ref = this.pending;
      _results = [];
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        dd = _ref[_i];
        _results.push(dd[1].resolve(dd[0](data)));
      }
      return _results;
    };

    return Defer;

  })();

  window.mq.all = function(arr) {
    var data, defer, defered, resolved, toresolve, _i, _len;
    resolved = 0;
    toresolve = arr.length;
    defer = new window.mq.Defer();
    data = [];
    for (_i = 0, _len = arr.length; _i < _len; _i++) {
      defered = arr[_i];
      defered.then(function(d) {
        data.push(d);
        resolved += 1;
        if (resolved === toresolve) {
          return defer.resolve(data);
        }
      });
    }
    return defer;
  };

  window.mq.stream = function(arr) {
    var defer, defered, _i, _len;
    defer = new window.mq.Defer();
    for (_i = 0, _len = arr.length; _i < _len; _i++) {
      defered = arr[_i];
      defered.then(function(d) {
        return defer.resolve(d);
      });
    }
    return defer;
  };

  sign = function(v) {
    if (v === 0) {
      return 0;
    }
    if (v < 0) {
      return -1;
    }
    return 1;
  };

  calculateSlide = function(tiles, e, x0, y0, x1, y1) {
    var col, dx, dy, moved, standedOn, sx, sy, t, touched, v, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1;
    dx = x1 - x0;
    dy = y1 - y0;
    sx = sign(dx);
    sy = sign(dy);
    touched = {};
    standedOn = {};
    _ref = tiles.intersectNonSolid(x0, y0, e);
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      t = _ref[_i];
      standedOn[t] = true;
      t.standingOn(e);
    }
    while (true) {
      moved = false;
      if (x0 !== x1 && sx !== 0) {
        col = tiles.intersectSolid(x0 + sx, y0, e);
        for (_j = 0, _len1 = col.length; _j < _len1; _j++) {
          v = col[_j];
          if (touched[v] === true) {
            continue;
          }
          v.touched(e);
          touched[v] = true;
        }
        if (col.length === 0) {
          x0 += sx;
          moved = true;
        }
      }
      if (y0 !== y1 && sy !== 0) {
        col = tiles.intersectSolid(x0, y0 + sy, e);
        for (_k = 0, _len2 = col.length; _k < _len2; _k++) {
          v = col[_k];
          if (touched[v] === true) {
            continue;
          }
          v.touched(e);
          touched[v] = true;
        }
        if (col.length === 0) {
          y0 += sy;
          moved = true;
        }
      }
      if (moved) {
        _ref1 = tiles.intersectNonSolid(x0, y0, e);
        for (_l = 0, _len3 = _ref1.length; _l < _len3; _l++) {
          t = _ref1[_l];
          if (standedOn[t] === true) {
            continue;
          }
          standedOn[t] = true;
          t.standingOn(e);
        }
      }
      if (!moved) {
        return [x0, y0];
      }
    }
  };

  calculateDeflection = function(t, x, y, w, h, dx, dy) {
    var b1, b2, col, remainingtime, sp, tile, tmin, vx, vy, _i, _len;
    b1 = {
      x: x,
      y: y,
      w: w,
      h: h,
      vx: dx,
      vy: dy
    };
    sp = [x, y, dx, dy];
    tmin = 1000000000;
    for (_i = 0, _len = t.length; _i < _len; _i++) {
      tile = t[_i];
      b2 = {
        x: tile.x,
        y: tile.y,
        w: 64,
        h: 64
      };
      col = window.physics.sweptAABB(b1, b2);
      if (col.t < tmin) {
        sp[0] = x + dx * col.t;
        sp[1] = y + dy * col.t;
        if (col.t === 1.0) {
          continue;
        }
        remainingtime = 1.0 - col.t;
        vx = dx;
        vy = dy;
        vx *= remainingtime;
        vy *= remainingtime;
        if (Math.abs(col.nx) > 0.0001) {
          vx = -vx;
        }
        if (Math.abs(col.ny) > 0.0001) {
          vy = -vy;
        }
        sp[2] = vx;
        sp[3] = vy;
      }
    }
    return sp;
  };

  aabbIntersect = function(a, b) {
    return (Math.abs(a.x - b.x) * 2 < (a.w + b.w)) && (Math.abs(a.y - b.y) * 2 < (a.h + b.h));
  };

  sweptAABB = function(b1, b2) {
    var entryTime, exitTime, normalx, normaly, xEntry, xExit, xInvEntry, xInvExit, yEntry, yExit, yInvEntry, yInvExit;
    if (aabbIntersect(b1, b2)) {
      return {
        t: 0.0,
        nx: 0,
        ny: 0
      };
    }
    xInvEntry = yInvEntry = xInvExit = yInvExit = 0.0;
    xEntry = yEntry = xExit = yExit = 0.0;
    if (b1.vx > 0.0) {
      xInvEntry = b2.x - (b1.x + b1.w);
      xInvExit = (b2.x + b2.w) - b1.x;
    } else {
      xInvEntry = (b2.x + b2.w) - b1.x;
      xInvExit = b2.x - (b1.x + b1.w);
    }
    if (b1.vy > 0.0) {
      yInvEntry = b2.y - (b1.y + b1.h);
      yInvExit = (b2.y + b2.h) - b1.y;
    } else {
      yInvEntry = (b2.y + b2.h) - b1.y;
      yInvExit = b2.y - (b1.y + b1.h);
    }
    if (b1.vx === 0.0) {
      xEntry = -Infinity;
      xExit = Infinity;
    } else {
      xEntry = xInvEntry / b1.vx;
      xExit = xInvExit / b1.vx;
    }
    if (b1.vy === 0.0) {
      yEntry = -Infinity;
      yExit = Infinity;
    } else {
      yEntry = yInvEntry / b1.vy;
      yExit = yInvExit / b1.vy;
    }
    if (yEntry > 1.0) {
      yEntry = -Infinity;
    }
    if (xEntry > 1.0) {
      xEntry = -Infinity;
    }
    entryTime = Math.max(xEntry, yEntry);
    exitTime = Math.min(xExit, yExit);
    if (xEntry > exitTime) {
      return {
        t: 1
      };
    }
    if (xEntry < 0.0 && yEntry < 0.0) {
      return {
        t: 1
      };
    }
    if (xEntry < 0.0 && (b1.x + b1.w < b2.x || b1.x > b2.x + b2.w)) {
      return {
        t: 1
      };
    }
    if (yEntry < 0.0 && (b1.y + b1.h < b2.y || b1.y > b2.y + b2.h)) {
      return {
        t: 1
      };
    }
    normalx = 0;
    normaly = 0;
    if (xEntry > yEntry) {
      if (xInvEntry < 0.0) {
        normalx = 1.0;
        normaly = 0.0;
      } else {
        normalx = -1.0;
        normaly = 0.0;
      }
    } else {
      if (yInvEntry < 0.0) {
        normalx = 0.0;
        normaly = 1.0;
      } else {
        normalx = 0.0;
        normaly = -1.0;
      }
    }
    return {
      nx: normalx * sign(b1.vx),
      ny: normaly * sign(b1.vy),
      t: entryTime
    };
  };

  line = function(x0, y0, x1, y1, fn) {
    var dx, dy, e2, err, sx, sy;
    x0 |= 0;
    y0 |= 0;
    x1 |= 0;
    y1 |= 0;
    dx = Math.abs(x1 - x0);
    dy = Math.abs(y1 - y0);
    sx = x0 < x1 ? 1 : -1;
    sy = y0 < y1 ? 1 : -1;
    err = dx - dy;
    while (true) {
      if (fn(x0, y0) === true) {
        return true;
      }
      if (x0 === x1 && y0 === y1) {
        return false;
      }
      e2 = 2 * err;
      if (e2 > -dy) {
        err -= dy;
        x0 += sx;
      }
      if (e2 < dx) {
        err += dx;
        y0 += sy;
      }
    }
  };

  window.physics = {
    sweptAABB: sweptAABB,
    line: line,
    calculateSlide: calculateSlide,
    calculateDeflection: calculateDeflection,
    sign: sign,
    dist: function(a, b) {
      var dx, dy;
      dx = a.x - b.x;
      dy = a.y - b.y;
      return Math.sqrt(dx * dx + dy * dy);
    }
  };

  window.Program = (function() {
    function Program(ctx) {
      this.ctx = ctx;
      this.gl = this.ctx.gl;
      this.vertexShader = this.gl.createShader(this.gl.VERTEX_SHADER);
      this.fragmentShader = this.gl.createShader(this.gl.FRAGMENT_SHADER);
      this.program = this.gl.createProgram();
    }

    Program.prototype.setFragSource = function(v) {
      this.gl.shaderSource(this.fragmentShader, v);
      this.gl.compileShader(this.fragmentShader);
      if (!this.gl.getShaderParameter(this.fragmentShader, this.gl.COMPILE_STATUS)) {
        console.error("ERROR in fragmentshader: \n" + this.gl.getShaderInfoLog(this.fragmentShader));
      }
      return this.gl.attachShader(this.program, this.fragmentShader);
    };

    Program.prototype.setVertSource = function(v) {
      this.gl.shaderSource(this.vertexShader, v);
      this.gl.compileShader(this.vertexShader);
      if (!this.gl.getShaderParameter(this.vertexShader, this.gl.COMPILE_STATUS)) {
        console.error("ERROR in vertexshader: \n" + this.gl.getShaderInfoLog(this.vertexShader));
      }
      return this.gl.attachShader(this.program, this.vertexShader);
    };

    Program.prototype.u1f = function(name, v) {
      var l;
      l = this.gl.getUniformLocation(this.program, name);
      return this.gl.uniform1f(l, v);
    };

    Program.prototype.u2f = function(name, x, y) {
      var l;
      l = this.gl.getUniformLocation(this.program, name);
      return this.gl.uniform2f(l, x, y);
    };

    Program.prototype.u3f = function(name, x, y, z) {
      var l;
      l = this.gl.getUniformLocation(this.program, name);
      return this.gl.uniform3f(l, x, y, z);
    };

    Program.prototype.u4f = function(name, x, y, z, w) {
      var l;
      l = this.gl.getUniformLocation(this.program, name);
      return this.gl.uniform4f(l, x, y, z, w);
    };

    Program.prototype.u1i = function(name, v) {
      var l;
      l = this.gl.getUniformLocation(this.program, name);
      return this.gl.uniform1i(l, v);
    };

    Program.prototype.u2i = function(name, x, y) {
      var l;
      l = this.gl.getUniformLocation(this.program, name);
      return this.gl.uniform2i(l, x, y);
    };

    Program.prototype.u3i = function(name, x, y, z) {
      var l;
      l = this.gl.getUniformLocation(this.program, name);
      return this.gl.uniform3i(l, x, y, z);
    };

    Program.prototype.u4i = function(name, x, y, z, w) {
      var l;
      l = this.gl.getUniformLocation(this.program, name);
      return this.gl.uniform4i(l, x, y, z, w);
    };

    Program.prototype.um2f = function(name, arr, t) {
      var l;
      if (t == null) {
        t = false;
      }
      l = this.gl.getUniformLocation(this.program, name);
      return this.gl.uniformMatrix2fv(l, t, arr);
    };

    Program.prototype.um3f = function(name, arr, t) {
      var l;
      if (t == null) {
        t = false;
      }
      l = this.gl.getUniformLocation(this.program, name);
      return this.gl.uniformMatrix3fv(l, t, arr);
    };

    Program.prototype.um4f = function(name, arr, t) {
      var l;
      if (t == null) {
        t = false;
      }
      l = this.gl.getUniformLocation(this.program, name);
      return this.gl.uniformMatrix4fv(l, t, arr);
    };

    Program.prototype.attachTexture = function(name, where, tex) {
      var me;
      me = this;
      return tex.loader.then(function() {
        me.gl.activeTexture(me.gl.TEXTURE0 + where);
        tex.bind();
        return me.u1i(name, where);
      });
    };

    Program.prototype.link = function() {
      this.gl.linkProgram(this.program);
      if (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) {
        console.error("Error when linking program: \n " + (this.gl.getProgramInfoLog()));
      }
      this.gl.validateProgram(this.program);
      if (!this.gl.getProgramParameter(this.program, this.gl.VALIDATE_STATUS)) {
        return console.error("Error when linking program: \n " + (this.gl.getProgramInfoLog()));
      }
    };

    Program.prototype.use = function() {
      var a;
      this.gl.useProgram(this.program);
      a = this.ctx.screen();
      return this.u4f("screen", a.x, a.y, 1.0, 1.0);
    };

    return Program;

  })();

  window.rnd = {
    choose: function(arr) {
      var i;
      i = Math.random() * arr.length;
      i |= 0;
      return arr[i];
    },
    rndCell: function(bounds) {
      var dx, dy, x, y;
      dx = bounds[2] - bounds[0];
      dy = bounds[3] - bounds[1];
      x = dx * Math.random();
      x |= 0;
      x += bounds[0];
      y = dy * Math.random();
      y |= 0;
      y += bounds[1];
      return [x, y];
    },
    chooseRndCellInAreas: function(arr) {
      return window.rnd.rndCell(window.rnd.choose(arr));
    }
  };

  vertShape = "precision highp float;\nattribute vec2 vertex;\nattribute vec4 vertexColor;\n\nuniform vec4 screen;\n\nvarying lowp vec4 color;\nvoid main() { \n  gl_Position = vec4(vertex, 1.0, 1.0) * screen; \n  color = vertexColor;\n}";

  fragShape = "precision highp float;\nvarying lowp vec4 color;\n\nvoid main() { \n  gl_FragColor = color; \n}";

  window.ShapeRender = (function() {
    function ShapeRender(g) {
      this.g = g;
      this.buffOutline = this.g.ctx.MeshBuffer();
      this.buffOutline.addDescription("vertex", "FLOAT", 2);
      this.buffOutline.addDescription("vertexColor", "FLOAT", 4);
      this.buffSolid = this.g.ctx.MeshBuffer();
      this.buffSolid.addDescription("vertex", "FLOAT", 2);
      this.buffSolid.addDescription("vertexColor", "FLOAT", 4);
      this.prog = this.g.ctx.Program();
      this.prog.setFragSource(fragShape);
      this.prog.setVertSource(vertShape);
      this.prog.link();
      this.io = 0;
      this.is = 0;
    }

    ShapeRender.prototype.setTransform = function(world) {
      return this.prog.um3f(world.getMatrix());
    };

    ShapeRender.prototype.drawLine = function(x0, y0, x1, y1, r, g, b, a) {
      this.buffOutline.pushff(x0, y0);
      this.buffOutline.pushffff(r, g, b, a);
      this.buffOutline.pushff(x1, y1);
      this.buffOutline.pushffff(r, g, b, a);
      this.buffOutline.pushii(this.io, this.io + 1);
      return this.io += 2;
    };

    ShapeRender.prototype.drawRectFilled = function(x0, y0, x1, y1, r, g, b, a) {
      this.buffSolid.pushff(x0, y0);
      this.buffSolid.pushffff(r, g, b, a);
      this.buffSolid.pushff(x1, y0);
      this.buffSolid.pushffff(r, g, b, a);
      this.buffSolid.pushff(x1, y1);
      this.buffSolid.pushffff(r, g, b, a);
      this.buffSolid.pushff(x0, y1);
      this.buffSolid.pushffff(r, g, b, a);
      this.buffSolid.pushiii(this.is, this.is + 1, this.is + 2);
      this.buffSolid.pushiii(this.is, this.is + 3, this.is + 2);
      return this.is += 4;
    };

    ShapeRender.prototype.render = function() {
      this.g.ctx.gl.lineWidth(4.0);
      this.buffOutline.upload();
      this.buffSolid.upload();
      this.prog.use();
      this.buffOutline.setup(this.prog);
      this.buffOutline.draw(this.g.ctx.gl.LINES);
      this.buffOutline.clear();
      this.buffSolid.setup(this.prog);
      this.buffSolid.draw();
      this.buffSolid.clear();
      this.io = 0;
      return this.is = 0;
    };

    return ShapeRender;

  })();

  window.Animation = (function() {
    var resetFrame;

    function Animation(name, frames) {
      this.name = name;
      this.frames = frames;
      this.frame = 0;
      this.frameWait = 32;
      this.last = Date.now();
    }

    resetFrame = function() {
      return this.frame = 0;
    };

    Animation.prototype.fps = function(fps) {
      return this.frameWait = 1000 / fps;
    };

    Animation.prototype.getFrame = function() {
      var delta;
      delta = Date.now() - this.last;
      this.last = Date.now();
      delta /= this.frameWait;
      this.frame += delta;
      return this.frames[(this.frame | 0) % this.frames.length];
    };

    return Animation;

  })();

  window.Sprite = (function() {
    function Sprite(w, h) {
      this.w = w;
      this.h = h;
      this.current = null;
    }

    Sprite.prototype.addAnimation = function(anim) {
      return this[anim.name] = anim;
    };

    Sprite.prototype.getFrame = function() {
      var r;
      if (this.current === null) {
        return [0, 0];
      }
      r = this.current.getFrame();
      return [r[0] * this.w, r[1] * this.h];
    };

    return Sprite;

  })();

  vertFont = "precision highp float;\nattribute vec2 vertex; \n\n\nuniform mat3 spriteTransform; \nuniform vec4 screen;\nuniform vec2 frame;\nuniform vec2 spriteSheetSize;\n\nvarying highp vec2 coord;\n\nvoid main() { \n  vec3 homogeniousCoord = vec3(vertex, 1.0);\n  gl_Position = vec4(homogeniousCoord * spriteTransform, 1.0) * screen; \n  coord = (vertex + frame) / spriteSheetSize;\n}";

  fragFont = "precision highp float;\nvarying highp vec2 coord;\nuniform sampler2D spriteTexture;\nuniform vec4 color;\n \nvoid main() { \n  gl_FragColor = texture2D(spriteTexture, coord) * color; \n}";

  window.SpriteRender = (function() {
    function SpriteRender(ctx) {
      var identity;
      this.buff = ctx.MeshBuffer(8);
      this.buff.addDescription("vertex", "FLOAT", 2);
      identity = new window.Transform2D();
      this.prog = ctx.Program();
      this.prog.setFragSource(fragFont);
      this.prog.setVertSource(vertFont);
      this.prog.link();
      this.prog.use();
      this.worldTransform = new window.Transform2D();
      this.prog.u4f("color", 1.0, 1.0, 1.0, 1.0);
      this.prog.um3f("spriteTransform", identity.getMatrix());
      this.texture = null;
    }

    SpriteRender.prototype.setSpriteSheet = function(texture, w, h) {
      this.texture = texture;
      this.w = w;
      this.h = h;
      this.prog.use();
      this.buff.clear();
      this.buff.pushff(0.0, 0.0);
      this.buff.pushff(this.w, 0.0);
      this.buff.pushff(this.w, this.h);
      this.buff.pushff(0.0, this.h);
      this.buff.pushiii(0, 1, 2);
      this.buff.pushiii(2, 3, 0);
      return this.buff.upload();
    };

    SpriteRender.prototype.use = function() {
      this.prog.use();
      this.buff.setup(this.prog);
      this.prog.u2f("spriteSheetSize", this.texture.width, this.texture.height);
      return this.prog.attachTexture("spriteTexture", 0, this.texture);
    };

    SpriteRender.prototype.setColor = function(r, g, b, a) {
      return this.prog.u4f("color", r, g, b, a);
    };

    SpriteRender.prototype.setWorldTransform = function(worldTransform) {
      return this.worldTransform = worldTransform;
    };

    SpriteRender.prototype.drawSprite = function(frame, spriteTransform) {
      if (this.texture === null) {
        return false;
      }
      if (this.texture.ready === false) {
        return false;
      }
      spriteTransform.translate(this.worldTransform.t[2], this.worldTransform.t[5]);
      this.prog.u2f("frame", frame[0], frame[1]);
      this.prog.um3f("spriteTransform", spriteTransform.getMatrix());
      this.buff.draw();
      return true;
    };

    return SpriteRender;

  })();

  window.Texture = (function() {
    function Texture(ctx, type, imageFormat, formatType, internalFormat) {
      this.ctx = ctx;
      this.type = type;
      this.imageFormat = imageFormat;
      this.formatType = formatType;
      this.internalFormat = internalFormat;
      this.gl = this.ctx.gl;
      if (this.internalFormat == null) {
        this.internalFormat = this.gl.RGBA;
      }
      if (this.imageFormat == null) {
        this.imageFormat = this.gl.RGBA;
      }
      if (this.formatType == null) {
        this.formatType = this.gl.UNSIGNED_BYTE;
      }
      if (this.type == null) {
        this.type = this.gl.TEXTURE_2D;
      }
      this.texture = this.gl.createTexture();
      this.filterNearest();
      this.width = 0;
      this.height = 0;
      this.ready = false;
    }

    Texture.prototype.getSampler = function() {
      return this.texture;
    };

    Texture.prototype.bind = function() {
      return this.gl.bindTexture(this.type, this.texture);
    };

    Texture.prototype.setImageData = function(imgDefer) {
      var me, _defer;
      this.ready = false;
      _defer = new window.mq.Defer();
      this.loader = _defer;
      me = this;
      imgDefer.then(function(img) {
        me.ready = true;
        me.width = img.width;
        me.height = img.height;
        me.bind();
        me.gl.texImage2D(me.type, 0, me.internalFormat, me.imageFormat, me.formatType, img);
        return _defer.resolve(true);
      });
      return _defer;
    };

    Texture.prototype.load = function(src) {
      return this.setImageData(window.loadImage(src));
    };

    Texture.prototype.filterNearest = function() {
      this.bind();
      this.gl.texParameteri(this.type, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
      return this.gl.texParameteri(this.type, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
    };

    Texture.prototype.filterLinear = function() {
      this.bind();
      this.gl.texParameteri(this.type, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
      return this.gl.texParameteri(this.type, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
    };

    return Texture;

  })();

  identity = function() {
    return new Float32Array([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]);
  };

  mult = function(a, b) {
    var d;
    d = new Float32Array(9);
    d[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6];
    d[1] = a[0] * b[1] + a[1] * b[4] + a[2] * b[7];
    d[2] = a[0] * b[2] + a[1] * b[5] + a[2] * b[8];
    d[3] = a[3] * b[0] + a[4] * b[3] + a[5] * b[6];
    d[4] = a[3] * b[1] + a[4] * b[4] + a[5] * b[7];
    d[5] = a[3] * b[2] + a[4] * b[5] + a[5] * b[8];
    d[6] = a[6] * b[0] + a[7] * b[3] + a[8] * b[6];
    d[7] = a[6] * b[1] + a[7] * b[4] + a[8] * b[7];
    d[8] = a[6] * b[2] + a[7] * b[5] + a[8] * b[8];
    return d;
  };

  window.Transform2D = (function() {
    function Transform2D() {
      this.t = identity();
      this.r = identity();
      this.s = identity();
      this.rotation = 0.0;
    }

    Transform2D.prototype.setTranslation = function(x, y) {
      this.t[2] = x;
      return this.t[5] = y;
    };

    Transform2D.prototype.translate = function(x, y) {
      this.t[2] += x;
      return this.t[5] += y;
    };

    Transform2D.prototype.setRotation = function(d) {
      var cos, sin;
      this.rotation = d;
      cos = Math.cos(this.rotation);
      sin = Math.sin(this.rotation);
      this.r[0] = this.r[4] = cos;
      this.r[1] = -sin;
      return this.r[3] = sin;
    };

    Transform2D.prototype.rotate = function(d) {
      var cos, sin;
      this.rotation = d + this.rotation;
      cos = Math.cos(this.rotation);
      sin = Math.sin(this.rotation);
      this.r[0] = this.r[4] = cos;
      this.r[1] = -sin;
      return this.r[3] = sin;
    };

    Transform2D.prototype.setScale = function(sx, sy) {
      if (sy == null) {
        sy = sx;
      }
      this.s[0] = sx;
      return this.s[4] = sy;
    };

    Transform2D.prototype.scale = function(sx, sy) {
      if (sy == null) {
        sy = sx;
      }
      this.s[0] *= sx;
      return this.s[4] *= sy;
    };

    Transform2D.prototype.getMatrix = function() {
      return mult(this.t, this.s);
    };

    return Transform2D;

  })();

}).call(this);
